﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
using System.Security.AccessControl;

namespace System.Peppers.Wmi
{
    /// <summary>
    /// The Win32_Share class represents a shared resource on a computer system running Windows. This may be a disk drive, printer, interprocess communication, or other shareable device.
    /// </summary>
    public sealed class Share : CimSetting
    {
        #region Static
        private static class WmiProperties
        {
            public const string
                AllowMaximum = "AllowMaximum",
                MaximumAllowed = "MaximumAllowed",
                Name = "Name",
                Path = "Path",
                Type = "Type";
        }

        private static class WmiMethods
        {
            public const string
                Create = "Create",
                Delete = "Delete",
                GetAccessMask = "GetAccessMask",
                SetShareInfo = "SetShareInfo";
        }

        private static class WmiParameters
        {
            public const string
                Path = "Path",
                Name = "Name",
                Type = "Type",
                MaximumAllowed = "MaximumAllowed",
                Description = "Description",
                Password = "Password",
                Access = "Access";
        }

        /// <summary>
        /// Enumerates shared resources on the system
        /// </summary>
        /// <returns>List of shares</returns>
        public static IEnumerable<Share> GetShares()
        {
            foreach (ManagementObject item in GetInstances(WmiClasses.Win32_Share))
            {
                yield return new Share(item);
            }
        }

        /// <summary>
        /// Enumerates shared resources on a remote system
        /// </summary>
        /// <param name="remoteParams">Connection options for remote system</param>
        /// <returns>List of shares</returns>
        public static IEnumerable<Share> GetShares(WmiRemoteParameters remoteParams)
        {
            foreach (ManagementObject item in GetInstances(WmiClasses.Win32_Share, remoteParams))
            {
                yield return new Share(item);
            }
        }

        /// <summary>
        /// The Create WMI class method initiates sharing for a server resource. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute Create. The Print operator can only add printer queues. The Communication operator can only add communication device queues.
        /// </summary>
        /// <param name="path">Local path of the Windows share.</param>
        /// <param name="name">Passes the alias to a path set up as a share on a computer system running Windows.</param>
        /// <param name="type">Passes the type of resource being shared. Types includes disk drives, print queues, interprocess communications (IPC), and general devices. Can be one of the following values.</param>
        /// <returns>Result of method</returns>
        public static ShareResult Create(string path, string name, ShareType type)
        {
            return Create(path, name, type, null, null, null, null);
        }

        /// <summary>
        /// The Create WMI class method initiates sharing for a server resource. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute Create. The Print operator can only add printer queues. The Communication operator can only add communication device queues.
        /// </summary>
        /// <param name="path">Local path of the Windows share.</param>
        /// <param name="name">Passes the alias to a path set up as a share on a computer system running Windows.</param>
        /// <param name="type">Passes the type of resource being shared. Types includes disk drives, print queues, interprocess communications (IPC), and general devices. Can be one of the following values.</param>
        /// <param name="maximumAllowed">Limit on the maximum number of users allowed to concurrently use this resource.</param>
        /// <param name="description">Optional comment to describe the resource being shared. This parameter is optional.</param>
        /// <param name="password">Password (when the server is running with share-level security) for the shared resource. If the server is running with user-level security, this parameter is ignored. This parameter is optional.</param>
        /// <param name="access">Security descriptor for user level permissions. A security descriptor contains information about the permissions, owner, and access capabilities of the resource. If this parameter is not supplied or is NULL, then Everyone has read access to the share.</param>
        /// <returns>Result of method</returns>
        public static ShareResult Create(string path, string name, ShareType type, uint? maximumAllowed, string description, string password, WmiSecurityDescriptor[] access)
        {
            Share share = new Share(WmiWrapper.GetStaticInstance(WmiClasses.Win32_Share));
            return share.ExecuteShareMethod(WmiMethods.Create, delegate(ManagementBaseObject inParam)
            {
                inParam[WmiParameters.Path] = path;
                inParam[WmiParameters.Name] = name;
                inParam[WmiParameters.Type] = type;
                inParam[WmiParameters.MaximumAllowed] = maximumAllowed;
                inParam[WmiParameters.Description] = description;
                inParam[WmiParameters.Password] = password;
                inParam[WmiParameters.Access] = access;
            });
        }

        /// <summary>
        /// The Create WMI class method initiates sharing for a server resource on a remote computer. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute Create. The Print operator can only add printer queues. The Communication operator can only add communication device queues.
        /// </summary>
        /// <param name="remoteParams">Connection options for remote system</param>
        /// <param name="path">Local path of the Windows share.</param>
        /// <param name="name">Passes the alias to a path set up as a share on a computer system running Windows.</param>
        /// <param name="type">Passes the type of resource being shared. Types includes disk drives, print queues, interprocess communications (IPC), and general devices. Can be one of the following values.</param>
        /// <returns>Result of method</returns>
        public static ShareResult Create(WmiRemoteParameters remoteParams, string path, string name, ShareType type)
        {
            return Create(remoteParams, path, name, type, null, null, null, null);
        }

        /// <summary>
        /// The Create WMI class method initiates sharing for a server resource on a remote computer. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute Create. The Print operator can only add printer queues. The Communication operator can only add communication device queues.
        /// </summary>
        /// <param name="remoteParams">Connection options for remote system</param>
        /// <param name="path">Local path of the Windows share.</param>
        /// <param name="name">Passes the alias to a path set up as a share on a computer system running Windows.</param>
        /// <param name="type">Passes the type of resource being shared. Types includes disk drives, print queues, interprocess communications (IPC), and general devices. Can be one of the following values.</param>
        /// <param name="maximumAllowed">Limit on the maximum number of users allowed to concurrently use this resource.</param>
        /// <param name="description">Optional comment to describe the resource being shared. This parameter is optional.</param>
        /// <param name="password">Password (when the server is running with share-level security) for the shared resource. If the server is running with user-level security, this parameter is ignored. This parameter is optional.</param>
        /// <param name="access">Security descriptor for user level permissions. A security descriptor contains information about the permissions, owner, and access capabilities of the resource. If this parameter is not supplied or is NULL, then Everyone has read access to the share.</param>
        /// <returns>Result of method</returns>
        public static ShareResult Create(WmiRemoteParameters remoteParams, string path, string name, ShareType type, uint? maximumAllowed, string description, string password, WmiSecurityDescriptor[] access)
        {
            using (Share share = new Share(WmiWrapper.GetStaticInstance(WmiClasses.Win32_Share, remoteParams)))
            {
                return share.ExecuteShareMethod(WmiMethods.Create, delegate(ManagementBaseObject inParam)
                {
                    inParam[WmiParameters.Path] = path;
                    inParam[WmiParameters.Name] = name;
                    inParam[WmiParameters.Type] = type;
                    inParam[WmiParameters.MaximumAllowed] = maximumAllowed;
                    inParam[WmiParameters.Description] = description;
                    inParam[WmiParameters.Password] = password;
                    inParam[WmiParameters.Access] = access;
                });
            }
        }
        #endregion

        internal Share(ManagementObject wmiObject)
            : base(wmiObject)
        { }

        /// <summary>
        /// Number of concurrent users for this resource has been limited. If true, the value in the MaximumAllowed property is ignored.
        /// </summary>
        public bool AllowMaximum
        {
            get { return Convert.ToBoolean(this[WmiProperties.AllowMaximum] ?? false); }
        }

        /// <summary>
        /// Limit on the maximum number of users allowed to use this resource concurrently. The value is only valid if the AllowMaximum property is set to FALSE.
        /// </summary>
        public uint? MaximumAllowed
        {
            get { return WmiUtil.ToNullable<uint>(this[WmiProperties.MaximumAllowed]); }
        }

        /// <summary>
        /// Alias given to a path set up as a share on a computer system running Windows.
        /// </summary>
        public string Name
        {
            get { return Convert.ToString(this[WmiProperties.Name]); }
        }

        /// <summary>
        /// Local path of the Windows share.
        /// </summary>
        public string Path
        {
            get { return Convert.ToString(this[WmiProperties.Path]); }
        }

        /// <summary>
        /// Type of resource being shared. Types include: disk drives, print queues, interprocess communications (IPC), and general devices.
        /// </summary>
        public ShareType Type
        {
            get { return (ShareType)Convert.ToUInt32(this[WmiProperties.Type] ?? 0); }
        }

        /// <summary>
        /// The Delete WMI class method deletes a share name from a server's list of shared resources, disconnecting connections to the shared resource. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute the method. The Print operator can delete only printer queues. The Communication operator can delete only communication-device queues.
        /// </summary>
        /// <returns>Result of method</returns>
        public ShareResult Delete()
        {
            return ExecuteShareMethod(WmiMethods.Delete, null);
        }

        /// <summary>
        /// The GetAccessMask method returns a uint32 bitmap with the access rights to the share held by the user or group on whose behalf the instance is returned.
        /// </summary>
        /// <returns>Access rights to the share held by the user or group.</returns>
        public FileSystemRights GetAccessMask()
        {
            using (ManagementBaseObject outParam = ExecuteMethod(WmiMethods.GetAccessMask, null))
            {
                return (FileSystemRights)Convert.ToUInt32(outParam[WmiClasses.ReturnValue]);
            }
        }

        /// <summary>
        /// The SetShareInfo WMI class method sets the parameters of a shared resource. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute SetShareInfo. The print operator can only set printer queues. The Communication operator can only set communication device queues.
        /// </summary>
        /// <param name="description">Optional comment to describe the resource being shared.</param>
        /// <returns>Result of method</returns>
        public ShareResult SetShareInfo(string description)
        {
            return SetShareInfo(null, description, null);
        }

        /// <summary>
        /// The SetShareInfo WMI class method sets the parameters of a shared resource. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute SetShareInfo. The print operator can only set printer queues. The Communication operator can only set communication device queues.
        /// </summary>
        /// <param name="maximumAllowed">Limit on the maximum number of users allowed to use this resource concurrently.</param>
        /// <param name="description">Optional comment to describe the resource being shared.</param>
        /// <returns>Result of method</returns>
        public ShareResult SetShareInfo(uint? maximumAllowed, string description)
        {
            return SetShareInfo(maximumAllowed, description, null);
        }

        /// <summary>
        /// The SetShareInfo WMI class method sets the parameters of a shared resource. Only members of the Administrators or Account Operators local group or those with Communication, Print, or Server operator group membership can successfully execute SetShareInfo. The print operator can only set printer queues. The Communication operator can only set communication device queues.
        /// </summary>
        /// <param name="maximumAllowed">Limit on the maximum number of users allowed to use this resource concurrently.</param>
        /// <param name="description">Optional comment to describe the resource being shared.</param>
        /// <param name="access">Security descriptor for user-level permissions. A security descriptor contains information about the permission, owner, and access capabilities of the resource.</param>
        /// <returns>Result of method</returns>
        public ShareResult SetShareInfo(uint? maximumAllowed, string description, WmiSecurityDescriptor access)
        {
            return ExecuteShareMethod(WmiMethods.SetShareInfo, delegate(ManagementBaseObject inParam)
            {
                inParam[WmiParameters.MaximumAllowed] = maximumAllowed;
                inParam[WmiParameters.Description] = description;
                inParam[WmiParameters.Access] = access;
            });
        }

        private ShareResult ExecuteShareMethod(string method, Action<ManagementBaseObject> callback)
        {
            using (ManagementBaseObject outParam = ExecuteMethod(method, callback))
            {
                return (ShareResult)Convert.ToUInt32(outParam[WmiClasses.ReturnValue]);
            }
        }
    }
}